﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FileHelpers;
using MoneyWentWhere.Utils;

namespace MoneyWentWhere.SimpleTextFile
{
    public class MwwDataFile
    {
        List<Account> _accounts = new List<Account>();

        public MwwDataFile() { }

        public List<Account> Accounts { get { return _accounts; } }

        /// <summary>
        /// Reassigns all transfer IDs sequentially.
        /// Useful for simplifying complex IDs.
        /// </summary>
        public void ReassignTransferIds()
        {
            Dictionary<String, int> txIds = new Dictionary<string,int>();
            int nextId = 1;

            foreach (Account a in Accounts)
            {
                foreach (Transaction t in a.Transactions)
                {
                    Transfer tfr = t as Transfer;
                    if (tfr != null)
                    {
                        tfr.Id = GetSimpleTransferId(tfr.Id, txIds, ref nextId);
                        tfr.TargetId = GetSimpleTransferId(tfr.TargetId, txIds, ref nextId);
                    }
                }
            }
        }

        String GetSimpleTransferId(String complexId, Dictionary<String, int> txIds, ref int nextId)
        {
            int simpleId;
            if (! txIds.TryGetValue(complexId, out simpleId))
            {
                // Add the Id if it does not exist
                simpleId = nextId++;
                txIds.Add(complexId, simpleId);
            }

            //Console.WriteLine(complexId + " -> id_" + simpleId); 

            return "id_" + simpleId;
        }

        #region Read/Write

        public void WriteFile(String filename)
        {
            using (MultiRecordEngine engine = GetFileEngine())
            {
                engine.WriteFile(filename, GetWriteItems());
            }
        }

        public String WriteString()
        {
            using (MultiRecordEngine engine = GetFileEngine())
            {
                return engine.WriteString(GetWriteItems());
            }
        }

        IEnumerable<object> GetWriteItems()
        {
            List<object> items = new List<object>();
            foreach (Account a in Accounts)
            {
                items.Add(a);
                items.AddRange(a.Transactions.ToArray());
            }
            return items;
        }

        public void ReadString(String fileContents)
        {
            using (MultiRecordEngine engine = GetFileEngine())
            {
                AddReadItems(engine.ReadString(fileContents));
            }
        }

        public void ReadFile(String filename)
        {
            using (MultiRecordEngine engine = GetFileEngine())
            {
                AddReadItems(engine.ReadFile(filename));
            }
        }

        private void AddReadItems(object[] items)
        {
            // Unpack
            foreach (Object item in items)
            {
                Account ac = item as Account;
                if (ac != null) { Accounts.Add(ac); }

                Transaction tx = item as Transaction;
                if (tx != null)
                {
                    // If there are no accounts, create a default one
                    if (Accounts.Count == 0)
                    {
                        Accounts.Add(new Account() { Currency = "USD", Name = "[Default]" });
                    }
                    Accounts.Last().Transactions.Add(tx);
                }
            }

            // TODO: 2nd pass integrity check (for transfers, balances etc.)
            foreach (Account ac in Accounts)
            {
                ac.OnAfterRead();
            }
        }

        MultiRecordEngine GetFileEngine()
        {
            MultiRecordEngine engine = new MultiRecordEngine(
                typeof(Account),

                typeof(Transaction),
                typeof(Reconcile),
                typeof(Transfer));

            engine.RecordSelector = new RecordTypeSelector(CustomSelector);
            engine.AfterWriteRecord += new EventHandler<AfterWriteRecordEventArgs>(engine_AfterWriteRecord); 
            return engine;
        }

        void engine_AfterWriteRecord(object sender, AfterWriteRecordEventArgs e)
        {
            if (e.Record is Account)
            {
                e.RecordLine = Environment.NewLine + e.RecordLine + Environment.NewLine +
                    new String('-', Math.Min(e.RecordLine.Length, 80));
            }
        }

        Type CustomSelector(MultiRecordEngine engine, string record)
        {
            // Comments
            if (record.Sw("-")) { return null; } 
            if (record.Sw("//")) { return null; }
            if (record.Sw("#")) { return null; } 

            if (record.Sw(Account.TypeId)) { return typeof(Account); }
         
            if (record.Sw(Reconcile.TypeId)) { return typeof(Reconcile); }
            if (record.Sw(Transfer.TypeId)) { return typeof(Transfer); }

            // Everything else is a simple Transaction   
            return typeof(Transaction);
        }

        #endregion
    }

    
}
